#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

namespace BlockQueueModule
{

    template <class T>
    class BlockQueue
    {
    private:
        bool IsFull() { return q.size() == _cap; }
        bool IsEmpty() { return q.empty(); }

    public:
        BlockQueue(int cap) :_cap(cap), pro_num(0), com_num(0)
        {
            pthread_mutex_init(&mutex, nullptr);
            pthread_cond_init(&condProduck, nullptr);
            pthread_cond_init(&condComsurmer, nullptr);
        }

        void Equeue(const T* in) // 生产者
        {
            pthread_mutex_lock(&mutex);

            while (IsFull())
            {
                pro_num++;
                pthread_cond_wait(&condProduck, &mutex);
                pro_num--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            q.push(*in);
            if(com_num)
            {
                printf("唤醒生产者\n");
                pthread_cond_signal(&condComsurmer);
            }
            pthread_mutex_unlock(&mutex);
        }
        void Pop(T* out) // 消费者
        {
            pthread_mutex_lock(&mutex);

            while (IsEmpty())
            {
                com_num++;
                pthread_cond_wait(&condComsurmer, &mutex);
                com_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }

            *out = q.front();
            q.pop();
            if(pro_num)
            {
                printf("唤醒生产者\n");
                pthread_cond_signal(&condProduck);
            }
            pthread_mutex_unlock(&mutex);

        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&mutex);
            pthread_cond_destroy(&condComsurmer);
            pthread_cond_destroy(&condProduck);
        }

    private:
        std::queue<T> q; // 使用队列方式控制资源进出
        int _cap; 
        pthread_mutex_t mutex;
        pthread_cond_t condComsurmer;
        pthread_cond_t condProduck;

        int pro_num ;
        int com_num ;
    };
};
